package io.gitee.chearnee.fw.redis;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.gitee.chearnee.fw.redis.serializer.HKeyRedisSerializer;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.StringCodec;
import org.redisson.codec.CompositeCodec;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

/**
 * @author cn
 * @version 1.0
 * @description
 * @date 2023/3/14 18:01
 */
@AutoConfiguration
public class FWRedisAutoConfiguration {
    @Bean
    @ConditionalOnClass(RedisOperations.class)
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory, Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        ObjectMapper build = jackson2ObjectMapperBuilder.build();
        buildTypeObjectMapper(build);
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(build, Object.class);
        template.setDefaultSerializer(jackson2JsonRedisSerializer);
        template.setKeySerializer(StringRedisSerializer.UTF_8);
        template.setHashKeySerializer(HKeyRedisSerializer.UTF_8);
        return template;
    }

    private void buildTypeObjectMapper(ObjectMapper build) {
        build.activateDefaultTyping(build.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
    }

    private Codec codec(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {
        ObjectMapper build = jackson2ObjectMapperBuilder.build();
        buildTypeObjectMapper(build);
        JsonJacksonCodec jsonJacksonCodec = new JsonJacksonCodec(build);
        return new CompositeCodec(StringCodec.INSTANCE, jsonJacksonCodec, jsonJacksonCodec);
    }

    @Bean
    @ConditionalOnClass(RedissonAutoConfiguration.class)
    public RedissonAutoConfigurationCustomizer customizer(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {
        return e -> e.setCodec(codec(jackson2ObjectMapperBuilder));
    }
}
